/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package map;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.ResourceBundle;
import javax.swing.JOptionPane;
import javax.xml.parsers.ParserConfigurationException;
import org.alternativevision.gpx.GPXParser;
import org.alternativevision.gpx.beans.GPX;
import org.alternativevision.gpx.beans.Track;
import org.alternativevision.gpx.beans.Waypoint;
import org.jdesktop.swingx.JXMapKit;
import org.jdesktop.swingx.JXMapViewer;
import org.jdesktop.swingx.mapviewer.DefaultWaypoint;
import org.jdesktop.swingx.mapviewer.DefaultWaypointRenderer;
import org.jdesktop.swingx.mapviewer.GeoPosition;
import org.jdesktop.swingx.mapviewer.WaypointPainter;
import org.jdesktop.swingx.painter.CompoundPainter;
import org.jdesktop.swingx.painter.Painter;
import org.xml.sax.SAXException;
import util.MapUtils;

/**
 *
 * @author Christoph
 */
public class MapManager {

    private JXMapKit jXMapKit;
    private Color[] colorArray;
    private volatile LinkedList<Line2D> trackLine;
    private CompoundPainter<JXMapViewer> painters;
    private TrackPainter trackPainter;
    private WaypointPainter<org.jdesktop.swingx.mapviewer.Waypoint> waypointPainter;

    /**
     * Konstruktor
     *
     * @param jXMapKit Karte, auf der gezeichnet werden soll
     */
    public MapManager(JXMapKit jXMapKit) {
        painters = new CompoundPainter<>();
        trackPainter = new TrackPainter();
        waypointPainter = new WaypointPainter<>();
        painters.addPainter(trackPainter);
        painters.addPainter(waypointPainter);
        
        this.jXMapKit = jXMapKit;
        this.jXMapKit.getMainMap().setOverlayPainter(painters);
        initColorArray();
        trackLine = new LinkedList<Line2D>();
    }

    /**
     * Füllt das Array mit Farben, die mit verwendet werden um Die Tracks in
     * unterschiedlichen Farben zu zeichnen
     */
    private void initColorArray() {

        colorArray = new Color[13];

        colorArray[0] = Color.RED;
        colorArray[1] = Color.GREEN;
        colorArray[2] = Color.BLUE;
        colorArray[3] = Color.YELLOW;
        colorArray[4] = Color.PINK;
        colorArray[5] = Color.BLACK;
        colorArray[6] = Color.GRAY;
        colorArray[7] = Color.ORANGE;
        colorArray[8] = Color.MAGENTA;
        colorArray[9] = Color.CYAN;
        colorArray[10] = Color.DARK_GRAY;
        colorArray[11] = Color.LIGHT_GRAY;
        colorArray[12] = Color.WHITE;


    }

    /**
     * Zeichnet die Tracks auf der Karte ein
     *
     * @param track Liste mit Tracks, die gezeichnet werden sollen
     */
    public void drawTrack(final ArrayList<Track> track) {
        // <editor-fold defaultstate="collapsed" desc="chris code">  


//        Painter<JXMapViewer> painter;
//        painter = new Painter<JXMapViewer>() {
//            //Implementieren der paint Methode
//            //(wie die Tracks gezeichnet werden)
//            @Override
//            public void paint(Graphics2D g, JXMapViewer map, int w, int h) {
//
//                Line2D line = new Line2D.Double();
//                g = (Graphics2D) g.create();
//                g.setStroke(new BasicStroke(2.0f));
//                Rectangle rect = map.getViewportBounds();
//                g.translate(-rect.x, -rect.y);
//
//
//
//                int colorCounter = 0;
//
//                // jeder Track wird durchlaufen, der in der Liste ist
//                for (int j = 0; j < track.size(); j++) {
//
//                    ArrayList<Waypoint> trackWaypoints = track.get(j).getTrackPoints();
//
//
//                    //Durchläuft die einzelnen Wegpunkte in einem Track
//                    for (int i = 0; i < trackWaypoints.size() - 1; i++) {
//                        //ermittel die zwei Wegpunkte
//                        GeoPosition geo1 = new GeoPosition(trackWaypoints.get(i).getLatitude(), trackWaypoints.get(i).getLongitude());
//                        GeoPosition geo2 = new GeoPosition(trackWaypoints.get(i + 1).getLatitude(), trackWaypoints.get(i + 1).getLongitude());
//
//                        Point2D startPt = map.getTileFactory().geoToPixel(geo1, map.getZoom());
//                        Point2D EndPt = map.getTileFactory().geoToPixel(geo2, map.getZoom());
//
//                        //verbindet die beiden Wegpunkte zu einer Linie
//                        line.setLine(startPt, EndPt);
//                        trackLine.add((Line2D) line.clone());
//                        g.setColor(colorArray[colorCounter]);
//                        g.draw(line);
//
//
//
//                    }
//
//                    if (j != track.size() - 1) {
//
//                        GeoPosition geo11 = new GeoPosition(trackWaypoints.get(trackWaypoints.size() - 1).getLatitude(), trackWaypoints.get(trackWaypoints.size() - 1).getLongitude());
//                        GeoPosition geo21 = new GeoPosition(track.get(j + 1).getTrackPoints().get(0).getLatitude(), track.get(j + 1).getTrackPoints().get(0).getLongitude());
//
//                        Point2D startPt = map.getTileFactory().geoToPixel(geo11, map.getZoom());
//                        Point2D EndPt = map.getTileFactory().geoToPixel(geo21, map.getZoom());
//
//                        //verbindet die beiden Wegpunkte zu einer Linie
//                        line.setLine(startPt, EndPt);
//                        trackLine.add((Line2D) line.clone());
//                        g.setColor(colorArray[colorCounter]);
//                        g.draw(line);
//
//                    }
//
//
//
//                    colorCounter++;
//
//                    if (colorCounter > 12) {
//                        colorCounter = 0;
//                    }
//
//
//
//                }
//
//            }
//        };        
//
//        jXMapKit.getMainMap().setOverlayPainter(painter);
//        jXMapKit.setCenterPosition(getPathCenterPoint(track));
//        jXMapKit.setZoom(7);
        
        //</editor-fold>

        trackPainter.clear();
        
        for (Track t: track) {
            for (Waypoint w: t.getTrackPoints()) {
                trackPainter.addPosition(new GeoPosition(w.getLatitude(), w.getLongitude()));
            }
        }
        
        jXMapKit.setCenterPosition(getPathCenterPoint(track));
        jXMapKit.setZoom(7);
    }

    public void paintGPSPoint(final GeoPosition geoPos) {
        // <editor-fold defaultstate="collapsed" desc="chris code">
//        Painter<JXMapViewer> painter;
//        painter = new Painter<JXMapViewer>() {
//            //Implementieren der paint Methode
//            //(wie die Tracks gezeichnet werden)
//            @Override
//            public void paint(Graphics2D g, JXMapViewer map, int w, int h) {
//
//
//                g = (Graphics2D) g.create();
//                g.setStroke(new BasicStroke(2.0f));
//                Rectangle rect = map.getViewportBounds();
//                g.translate(-rect.x, -rect.y);
//
//
//
//                g.setColor(Color.RED);
//                if (!MapManager.this.trackLine.isEmpty()) {
//                    for (Line2D line2 : trackLine) {
//                        g.draw(line2);
//                    }
//                }
//
//
//
//                DefaultWaypointRenderer renderer = new DefaultWaypointRenderer();
//                renderer.paintWaypoint(g, map, new org.jdesktop.swingx.mapviewer.Waypoint() {
//                    @Override
//                    public GeoPosition getPosition() {
//                        return geoPos;
//                    }
//                });
//
//
//
//            }
//        };
//
//        jXMapKit.getMainMap().setOverlayPainter(painter);

        //</editor-fold>
        waypointPainter.setWaypoints(new HashSet<>(Arrays.asList(new DefaultWaypoint[] { new DefaultWaypoint(geoPos) })));
        jXMapKit.repaint();
    }
    
    public void paintGPSPoints(List<GeoPosition> positions) {
        HashSet<DefaultWaypoint> waypoints = new HashSet<>();
        
        for (GeoPosition pos: positions) {
            waypoints.add(new DefaultWaypoint(pos));
        }
        
        waypointPainter.setWaypoints(waypoints);
        jXMapKit.repaint();
    }

    /**
     *
     * @param trackList Liste von Tracks, von denen das Center erechnet werden
     * soll
     *
     * @return center_point gibt den Punkt zurück, der in der Mitte der Tracks
     * liegt
     */
    private GeoPosition getPathCenterPoint(ArrayList<Track> trackList) {

        GeoPosition center_point;
        double highLatitude, lowLatitude, highLongitude, lowLongitude;



        highLatitude = trackList.get(0).getTrackPoints().get(0).getLatitude();
        lowLatitude = trackList.get(0).getTrackPoints().get(0).getLatitude();
        highLongitude = trackList.get(0).getTrackPoints().get(0).getLongitude();
        lowLongitude = trackList.get(0).getTrackPoints().get(0).getLongitude();

        for (Track track : trackList) {


            for (Waypoint wayPoint : track.getTrackPoints()) {
                if (wayPoint.getLatitude() > highLatitude) {
                    highLatitude = wayPoint.getLatitude();
                }

                if (wayPoint.getLatitude() < lowLatitude) {
                    lowLatitude = wayPoint.getLatitude();
                }

                if (wayPoint.getLongitude() > highLongitude) {
                    highLongitude = wayPoint.getLongitude();
                }

                if (wayPoint.getLongitude() < lowLongitude) {
                    lowLongitude = wayPoint.getLongitude();
                }
            }
        }

        center_point = new GeoPosition((highLatitude + lowLatitude) / 2, (highLongitude + lowLongitude) / 2);

        return center_point;
    }
    
    public static float getDistanceByGPXFile(String path) throws IOException, ParserConfigurationException, SAXException {
        GPXParser p = new GPXParser();
        FileInputStream in = new FileInputStream(path);
        GPX gpx = p.parseGPX(in);


        HashSet<Track> tracks = gpx.getTracks();

        double distance = 0.0;
        
        for (Track t: tracks) {
            ArrayList<Waypoint> waypoints = t.getTrackPoints();
            for (int i = 0; i < waypoints.size() - 1; i++) {
                distance += MapUtils.calcDistance(
                        new GeoPosition(
                            waypoints.get(i).getLatitude(),
                            waypoints.get(i).getLongitude()),
                        new GeoPosition(
                            waypoints.get(i + 1).getLatitude(),
                            waypoints.get(i + 1).getLongitude())
                        );
            }
        }
        
        return ((Double)distance).floatValue();
    }

    /**
     * Liest eine GPX-Datei ein und verarbeitet sie
     *
     * @param path Pfad der .gpx Datei
     */
    public ArrayList<Track> importGPX(String path) {

        ArrayList<Track> array = null;

        try {
            GPXParser p = new GPXParser();
            FileInputStream in = new FileInputStream(path);
            GPX gpx = p.parseGPX(in);


            HashSet<Track> points = gpx.getTracks();



            array = new ArrayList<Track>(points);

            drawTrack(array);







        } catch (IOException e) {
            JOptionPane.showMessageDialog(null, ResourceBundle.getBundle("gui/guilabels").getString("errorparsinggpx"), ResourceBundle.getBundle("gui/guilabels").getString("error"), JOptionPane.ERROR_MESSAGE);
        } catch (ParserConfigurationException | SAXException ex) {
            JOptionPane.showMessageDialog(null, ResourceBundle.getBundle("gui/guilabels").getString("errorparsinggpx"), ResourceBundle.getBundle("gui/guilabels").getString("error"), JOptionPane.ERROR_MESSAGE);
        }

        return array;
    }
}
